package cn.iocoder.yudao.module.contract.controller.admin.invoice;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.module.contract.controller.admin.order.vo.OrderSyncReqVO;
import cn.iocoder.yudao.module.contract.dal.dataobject.company.CompanyDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.invoice.InvoiceDetailsDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.invoice.InvoiceOrdersDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.invoiceContract.InvoiceContractDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.order.OrderDO;
import cn.iocoder.yudao.module.contract.dal.dataobject.orderContract.OrderContractDO;
import cn.iocoder.yudao.module.contract.dal.mysql.invoice.InvoiceDetailsMapper;
import cn.iocoder.yudao.module.contract.service.company.CompanyService;
import cn.iocoder.yudao.module.contract.service.invoice.InvoiceOrdersService;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;

import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.math.BigDecimal;
import java.util.*;
import java.io.IOException;
import java.util.stream.Collectors;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;

import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;

import cn.iocoder.yudao.module.contract.controller.admin.invoice.vo.*;
import cn.iocoder.yudao.module.contract.dal.dataobject.invoice.InvoiceDO;
import cn.iocoder.yudao.module.contract.service.invoice.InvoiceService;

@Tag(name = "管理后台 - 发票")
@RestController
@RequestMapping("/contract/invoice")
@Validated
public class InvoiceController {

    @Resource
    private InvoiceService invoiceService;
    @Resource
    private CompanyService companyService;
    @Resource
    private InvoiceDetailsMapper invoiceDetailsMapper;
    @Resource
    private InvoiceOrdersService invoiceOrdersService;

    @GetMapping("/get")
    @Operation(summary = "获得发票")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
//    @PreAuthorize("@ss.hasPermission('contract:invoice:query')")
    public CommonResult<InvoiceRespVO> getInvoice(@RequestParam("id") Long id) {
        InvoiceDO invoice = invoiceService.getInvoice(id);
        return success(BeanUtils.toBean(invoice, InvoiceRespVO.class));
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除客户")
    @Parameter(name = "id", description = "编号", required = true)
//    @PreAuthorize("@ss.hasPermission('contract:client:delete')")
    public CommonResult<Boolean> deleteClient(@RequestParam("id") Long id) {
        InvoiceDO invoice = invoiceService.getInvoice(id);
        if(invoice==null){
            return error("发票不存在");
        }
        if(!"-2".equals(invoice.getStatus())){
            return error("发票未关闭，无法删除");
        }
        invoiceService.removeById(id);
        return success(true);
    }

    @GetMapping("/getDetails")
    @Operation(summary = "获得发票详情")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
//    @PreAuthorize("@ss.hasPermission('contract:invoice:query')")
    public CommonResult<?> getDetails(@RequestParam("id") Long id) {
        Map<String,Object> data = new HashMap<>();
        InvoiceDO invoice = invoiceService.getInvoice(id);
        if(invoice==null){
            return error("发票不存在");
        }
        InvoicePageReqVO pageReqVO = new InvoicePageReqVO();
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<InvoiceOrdersDO> ordersList = invoiceService.getInvoiceOrdersPage(pageReqVO,invoice.getDdSqkpRecordId()).getList();
        List<InvoiceDetailsDO> detailsList = invoiceService.getInvoiceDetailsPage(pageReqVO,invoice.getZskpId()).getList();
        data.put("invoice",invoice);
        data.put("ordersList",ordersList);
        data.put("detailsList",detailsList);
        return success(data);
    }

    @GetMapping("/page")
    @Operation(summary = "获得发票分页")
//    @PreAuthorize("@ss.hasPermission('contract:invoice:query')")
    public CommonResult<PageResult<InvoiceRespVO>> getInvoicePage(@Valid InvoicePageReqVO pageReqVO) {
        PageResult<InvoicePageRespVO> pageResult = invoiceService.getInvoicePage(pageReqVO);
        return success(BeanUtils.toBean(pageResult, InvoiceRespVO.class));
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出发票 Excel")
//    @PreAuthorize("@ss.hasPermission('contract:invoice:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportInvoiceExcel(@Valid InvoicePageReqVO pageReqVO,
              HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<InvoicePageRespVO> list = invoiceService.getInvoicePage(pageReqVO).getList();

            if("0".equals(pageReqVO.getListType())){
            // 导出 Excel
            ExcelUtils.write(response, "发票总表.xls", "数据", InvoiceExportVO.class,
                    BeanUtils.toBean(list, InvoiceExportVO.class));
        }else{
            // 导出 Excel
            ExcelUtils.write(response, "发票管理.xls", "数据", InvoiceManageExportVO.class,
                    BeanUtils.toBean(list, InvoiceManageExportVO.class));
        }
    }

    // ==================== 子表（发票明细） ====================

    @GetMapping("/invoice-details/page")
    @Operation(summary = "获得发票明细分页")
    @Parameter(name = "invoiceId", description = "发票id")
//    @PreAuthorize("@ss.hasPermission('contract:invoice:query')")
    public CommonResult<PageResult<InvoiceDetailsDO>> getInvoiceDetailsPage(PageParam pageReqVO,
                                                                            @RequestParam("zskpId") String zskpId) {
        return success(invoiceService.getInvoiceDetailsPage(pageReqVO, zskpId));
    }

	@GetMapping("/invoice-details/get")
	@Operation(summary = "获得发票明细")
	@Parameter(name = "id", description = "编号", required = true)
//    @PreAuthorize("@ss.hasPermission('contract:invoice:query')")
	public CommonResult<InvoiceDetailsDO> getInvoiceDetails(@RequestParam("id") Long id) {
	    return success(invoiceService.getInvoiceDetails(id));
	}

    // ==================== 子表（发票订单信息） ====================

    @GetMapping("/invoice-orders/page")
    @Operation(summary = "获得发票订单信息分页")
    @Parameter(name = "zskpId", description = "税票ID号")
//    @PreAuthorize("@ss.hasPermission('contract:invoice:query')")
    public CommonResult<PageResult<InvoiceOrdersDO>> getInvoiceOrdersPage(PageParam pageReqVO,
                                                                          @RequestParam("zskpId") String zskpId) {
        return success(invoiceService.getInvoiceOrdersPage(pageReqVO, zskpId));
    }

	@GetMapping("/invoice-orders/get")
	@Operation(summary = "获得发票订单信息")
	@Parameter(name = "id", description = "编号", required = true)
//    @PreAuthorize("@ss.hasPermission('contract:invoice:query')")
	public CommonResult<InvoiceOrdersDO> getInvoiceOrders(@RequestParam("id") Long id) {
	    return success(invoiceService.getInvoiceOrders(id));
	}

    @PostMapping("/invoiceSync")
    @Operation(summary = "发票同步")
    public CommonResult<?> invoiceSync(@RequestParam("startDate") String startDate,@RequestParam("endDate") String endDate) {
        String result = invoiceService.invoiceSync(startDate,endDate);
        if(result.contains("同步失败-")){
            return error(result);
        }
        return success(result);
    }

    @PostMapping("/updateStatus")
    @Operation(summary = "修改发票状态")
    public CommonResult<?> updateStatus(@RequestParam("id") Long id,@RequestParam("status") String status) {
        InvoiceDO invoiceDO = invoiceService.getInvoice(id);
        if(ObjectUtil.isNull(invoiceDO)){
            return error("发票数据不存在");
        }
        if(!"-2".equals(status) && !"0".equals(status)){
            return error("传入的状态异常");
        }
        if("-2".equals(invoiceDO.getStatus()) || "0".equals(invoiceDO.getStatus()) || "2".equals(invoiceDO.getStatus())){
            InvoiceDO invoice = new InvoiceDO();
            invoice.setId(id);
            invoice.setStatus(status);
            invoiceService.updateById(invoice);
        }else{
            return error("当前发票状态无法操作");
        }
        return success("操作成功");
    }

    @PostMapping("/generateContract")
    @Operation(summary = "合同生成")
    public CommonResult<?> generateContract(@RequestBody GenerateContractVO generateContractVO) {
        if(StringUtils.isBlank(generateContractVO.getType()) && StringUtils.isBlank(generateContractVO.getIds())){
            return error("请求参数不正确");
        }
        if("1".equals(generateContractVO.getType()) && StringUtils.isBlank(generateContractVO.getIds())){
            return error("请选择需要生成合同的订单");
        }
        if(StringUtils.isBlank(generateContractVO.getOperateType())){
            generateContractVO.setOperateType("1");
        }
        String result = invoiceService.generateContract(generateContractVO);
        if("2".equals(generateContractVO.getOperateType())){
            return success(result);
        }
        return success("操作成功");
    }

    @PostMapping("/getSigningDate")
    @Operation(summary = "获取签订日期")
    public CommonResult<?> getSigningDate(@RequestBody GenerateContractVO generateContractVO) {
        //发票数据
        List<InvoiceDO> list = null;
        //借贷项发票
        List<InvoiceDO> list1 = null;
        String signingDate = "";
        list = invoiceService.list(Wrappers.<InvoiceDO>lambdaQuery().in(InvoiceDO::getId,Arrays.asList(generateContractVO.getIds().split(","))).in(InvoiceDO::getStatus, Arrays.asList("0,2".split(","))).ne(InvoiceDO::getVsbed,"").isNotNull(InvoiceDO::getVsbed));
        list1 = invoiceService.list(Wrappers.<InvoiceDO>lambdaQuery().in(InvoiceDO::getId,Arrays.asList(generateContractVO.getIds().split(","))).in(InvoiceDO::getStatus, Arrays.asList("0,2".split(","))).and(i->i.eq(InvoiceDO::getVsbed,"").or().isNull(InvoiceDO::getVsbed)));

        if(list ==null || list.size()==0) {
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"无可生成合同的发票数据");
        }
        Map<String, List<InvoiceDO>> invoicesMap = list.stream().collect(Collectors.groupingBy(item -> item.getXfmc() + "-" + item.getGfmc()+ "-" +item.getVsbed()));
        Map<String, List<InvoiceDO>> invoicesMap1 = list1.stream().collect(Collectors.groupingBy(item -> item.getXfmc() + "-" + item.getGfmc()));
        if(invoicesMap.size()>1){
            throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"请选择售达方、公司主体、运输方式一致的发票数据");
        }
        for (String key : invoicesMap.keySet()) {
            List<InvoiceDO> invoiceList = invoicesMap.get(key);
            String xfmcGfmcKey = key.substring(0, key.lastIndexOf("-"));
            List<InvoiceDO> invoiceList1 = invoicesMap1.get(xfmcGfmcKey);
                if(invoiceList1!=null && invoiceList1.size()>0){
                invoiceList.addAll(invoiceList1);
            }
            if (invoiceList.size() > 0) {
                InvoiceDO maxInvoice = invoiceList.stream().max(Comparator.comparing(InvoiceDO::getKprq)).get();
                InvoiceDO minInvoice = invoiceList.stream().min(Comparator.comparing(InvoiceDO::getKprq)).get();
                CompanyDO company = companyService.getOne(Wrappers.<CompanyDO>lambdaQuery().eq(CompanyDO::getCompanyName, maxInvoice.getGfmc()));
                if (!"3".equals(generateContractVO.getType())) {
                    List<String> zskpIds = invoiceList.stream().map(InvoiceDO::getZskpId).collect(Collectors.toList());
                    List<Map<String, Object>> detailsSumList = invoiceDetailsMapper.selectMaps(Wrappers.<InvoiceDetailsDO>query().select("ggxh, hsdj ,sum(hsje) as hsjeTotal ,sum(sl) as slTotal").ne("sl","").in("zskp_id", zskpIds).groupBy("ggxh", "hsdj").having("SUM(hsje) <= 0 or SUM(sl) <= 0"));
                    if (detailsSumList.size() > 0) {
                        throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(), "明细数据存在金额或数量统计为负数");
                    }
                }
                if (company != null) {
                    //公司间签订日期：最早的开票月份的一号
                        signingDate = minInvoice.getInvoiceMonth() + "-01";
                } else {
                    if ("3".equals(generateContractVO.getType())) {
                        //退货协议订日期：最早的发货单过账日期
                        List<String> ddSqkpRecordIds = invoiceList.stream().map(InvoiceDO::getDdSqkpRecordId).collect(Collectors.toList());
                        InvoiceOrdersDO invoiceOrders = invoiceOrdersService.getOne(Wrappers.<InvoiceOrdersDO>lambdaQuery().in(InvoiceOrdersDO::getDdSqkpRecordId, ddSqkpRecordIds).orderByAsc(InvoiceOrdersDO::getWadatLst), false);
                        if (invoiceOrders == null) {
                            continue;
                        }
                        signingDate = DateUtil.format(invoiceOrders.getWadatLst(), "yyyy-MM-dd");
                    } else {
                        //其他：最早的开票日期
                        signingDate = DateUtil.formatDate(DateUtil.parseDateTime(minInvoice.getKprq()));
                    }
                }
            }
        }

        return success(signingDate);
    }

}